package SPAN::Controller::Method;

use strict;
use warnings;
use base 'Reaction::UI::Controller';
use aliased 'SPAN::UI::ViewPort::ActionForm';
use aliased 'Reaction::UI::ViewPort';

sub base : Chained('/base') : PathPart('method') : CaptureArgs(0) {
    my ( $self, $c ) = @_;
    $self->push_viewport( ViewPort, layout => 'method_menu.tt' );
}

sub method : Chained('base') : PathPart('') : CaptureArgs(1) {
    ( my ( $self, $c ), my $method : Stashed ) = @_;
}

sub run : Chained('method') : Args(0) {
    my ( $self, $c ) = @_;
    $self->add_to_menu( 'Method List' => $c->uri_for('/') );
    $self->add_to_menu(
        'Reset' => $c->uri_for( $c->action, $c->req->captures ) );

    $c->forward('Model::Method');
    my $action : Stashed;
    my $title : Stashed = $action->display_name;

    $self->push_viewport( ActionForm,
        action            => $action,
        layout            => 'form.tt',
        on_apply_callback => sub { $self->on_run_callback( $c => @_ ) }
    );
}

sub result : Private {
    my ( $self, $c ) = @_;
    my $result : Stashed;
    my $var = $c->stash->{action}->variable;
    my $y = join ',', map { $_->{x} } @{ $result->{partial_results} };
    my $x = join ',', 1 .. @{ $result->{partial_results} };

    my $graphx : Stashed
        = $c->uri_for( $c->controller('Image')->action_for('chart'),
        'png', { x => $x, y => $y, legend => 'Convergência de ' . $var } );

    $y = join ',', map { $_->{y} } @{ $result->{partial_results} };

    my $graphy : Stashed
        = $c->uri_for( $c->controller('Image')->action_for('chart'),
        'png', { x => $x, y => $y, legend => 'Convergência de f(' . $var . ')' } );

    my $method : Stashed;
    $self->push_viewport( ViewPort, layout => "method/${method}.tt" );
}

sub error : Private {
    my ( $self, $c ) = @_;
    my $result : Stashed;
    $self->push_viewport( ViewPort, layout => 'method/error.tt' );
}

sub on_run_callback {
    ( my ( $self, $c, $vp ), my $result : Stashed ) = @_;
    if ( exists $result->{error} ) {
        $c->forward( $self->action_for('error') );
    }
    else {
        $c->forward( $self->action_for('result') );
    }
}

sub process : Private {
    my ( $self, $c ) = @_;
    my $categories : Stashed = $c->model('Method')->categories;
    foreach my $category (@$categories) {
        foreach my $method ( keys %{ $category->{methods} } ) {
            $category->{methods}{$method}{uri}
                = $c->uri_for( $self->action_for('run'), [$method] );
            $category->{methods}{$method}{help_uri}
                = $c->uri_for( $self->action_for('help_method'), [$method] );
        }
    }
}

sub add_to_menu {
    my ( $self, $label, $uri ) = @_;
    my $method_menu : Stashed;
    push @{$method_menu},
        {
        url   => $uri,
        label => $label
        };
}

sub help : Chained('base') : Args(0) {
    my ( $self, $c ) = @_;
    my $title : Stashed = 'Help';
    $self->add_to_menu( 'Method List' => $c->uri_for('/') );
    $c->forward('process');
    $self->push_viewport( ViewPort, layout => "help/method.tt" );
}

sub help_method : Chained('method') : PathPart('help') : Args(0) {
    my ( $self, $c ) = @_;
    $self->add_to_menu(
        'Help Index' => $c->uri_for( $c->action_for('help') ) );
    my $method : Stashed;
    $self->push_viewport( ViewPort, layout => "help/${method}.tt" );
}

sub multi : Chained('base') Args(0) {
    my ( $self, $c ) = @_;
    my $title : Stashed = 'Non Linear Equations';
    $self->add_to_menu( 'Method List' => $c->uri_for('/') );
    my ($category)
        = grep { $_->{display_name} eq 'Non Linear Equations' }
        @{ $c->model('Method')->categories };
    my $action = $c->model('Multi::Method')
        ->new( target_model => $category, ctx => $c );
    $self->push_viewport( ActionForm,
        action            => $action,
        layout            => 'form.tt',
        on_apply_callback => sub { $self->on_multirun_callback( $c => @_ ) }
    );
}

sub on_multirun_callback {
    ( my ( $self, $c, $vp ), my $results : Stashed ) = @_;

    if ( ref $results eq 'HASH' && exists $results->{error} ) {
        $c->forward( $self->action_for('error') );
    }
    else {
        $c->forward( $self->action_for('results') );
    }
}

sub results : Private {
    my ( $self, $c ) = @_;
    $self->push_viewport( ViewPort, layout => 'method/results.tt' );
}

=head1 AUTHOR

Wallace Reis

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

1;
